package com.zues.thread.lock.cas.atomic;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicIntegerArray;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * 演示原子数组的操作
 *
 * @author zues
 * @date 3/11/2025 9:15 下午
 */
public class AtomicArrayDemo {

    public static void main(String[] args) {

        //使用普通数组，线程不安全  [5476, 5434, 5360, 5411, 5324, 5355, 5306, 5295, 5515, 5561]
        demo(() -> new int[10],
                (array) -> array.length,
                (array, index) -> array[index]++,
                array -> System.out.println(Arrays.toString(array)));

        //使用原子数组,可以保证线程安全，操作是原子性的 [10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000]
//        demo(() -> new AtomicIntegerArray(10),
//                (array) -> array.length(),
//                (array, index) -> array.getAndIncrement(index),
//                array -> System.out.println(array));

        //上面的写法等于下面的写法：
        demo(() -> new AtomicIntegerArray(10),
                AtomicIntegerArray::length,
                AtomicIntegerArray::getAndIncrement,
                System.out::println);


    }

    /**
     * @param arraySupplier 提供数组，可以是线程不安全数组或线程安全数组
     * @param lengthFun     获取数组长度的方法
     * @param putConsumer   自增方法，回传array，index
     * @param printConsumer 打印数组的方法
     * @param <T>
     */
    //函数式接口复习
    //supplier 提供者 无中生有 ()->结果
    //function 函数 一个参数一个结果  (参数)->结果， BiFunction (参数1,参数2)->结果
    //consumer 消费者 一个参数没结果 (参数)->void， BiConsumer (参数1,参数2)->void
    private static <T> void demo(
            Supplier<T> arraySupplier,
            Function<T, Integer> lengthFun,
            BiConsumer<T, Integer> putConsumer,
            Consumer<T> printConsumer) {

        List<Thread> ts = new ArrayList<>();
        T array = arraySupplier.get();
        int length = lengthFun.apply(array);
        for (int i = 0; i < length; i++) {
            ts.add(new Thread(() -> {
                for (int j = 0; j < 10000; j++) {
                    putConsumer.accept(array, j % length);
                }
            }));
        }
        ts.forEach(Thread::start); //启动所有线程
        ts.forEach(t -> {
            try {
                t.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }); //等待所有线程结束
        printConsumer.accept(array);

    }

}


